package model

import (
	"context"
	"fmt"
	"time"

	"gitee.com/liuxuezhan/ar-platform/login-rpc/internal/dao/schema"
	"gitee.com/liuxuezhan/ar-platform/login-rpc/internal/svc"

	"github.com/zeromicro/go-zero/core/logc"
	"gorm.io/gorm"
)

type UserLoginTokenModel struct {
	ctx context.Context
	db  *gorm.DB
}

func NewUserLoginTokenModel(ctx context.Context, db *gorm.DB) *UserLoginTokenModel {
	return &UserLoginTokenModel{
		ctx: ctx,
		db:  db,
	}
}

func (model *UserLoginTokenModel) getDb() *gorm.DB {
	if model.db != nil {
		return model.db
	}

	return svc.Db
}

func (model *UserLoginTokenModel) GetUserLoginTokenByUserIdAndSource(userId int64, source string, business string) (id int64, err error) {
	table := schema.SubtableUserId(userId, schema.UserLoginToken{}.TableName())
	dbRes := model.getDb().Model(&schema.UserLoginToken{}).Table(table).Select("id").Where("user_id =? and source = ? and business = ?", userId, source, business).First(&id)
	if err := dbRes.Error; err != nil && err != gorm.ErrRecordNotFound {
		logc.Error(model.ctx, "UserLoginTokenModel-GetUserLoginTokenByUserIdAndSource,err:", err)
		return id, err
	}

	return id, nil
}

func (model *UserLoginTokenModel) InsertUserLoginToken(data *schema.UserLoginToken) error {
	table := schema.SubtableUserId(data.UserId, schema.UserLoginToken{}.TableName())
	data.CreatedAt = time.Now().Unix()
	data.UpdatedAt = time.Now().Unix()
	dbRes := model.getDb().Model(&schema.UserLoginToken{}).Table(table).Create(data)
	if err := dbRes.Error; err != nil {
		logc.Error(model.ctx, "UserLoginTokenModel-InsertUserLoginToken,err:", err)
		return err
	}

	return nil
}

func (model *UserLoginTokenModel) UpdateUserLoginToken(id int64, token string, userId int64) error {
	table := schema.SubtableUserId(userId, schema.UserLoginToken{}.TableName())
	dbRes := model.getDb().Model(&schema.UserLoginToken{}).Table(table).Where("id=?", id).Update("sign", token)
	if err := dbRes.Error; err != nil {
		logc.Error(model.ctx, "UserLoginTokenModel-UpdateUserLoginToken,err:", err)
		return err
	}

	return nil
}

func (model *UserLoginTokenModel) GetSignByUserIdAndPlatform(userId int64, platform string, business string) (sign string, err error) {
	table := schema.SubtableUserId(userId, schema.UserLoginToken{}.TableName())
	dbRes := model.getDb().Model(&schema.UserLoginToken{}).Table(table).Select("sign").Where("user_id =? and source = ? and business=?", userId, platform, business).First(&sign)
	if err := dbRes.Error; err != nil && err != gorm.ErrRecordNotFound {
		logc.Error(model.ctx, "UserLoginTokenModel-GetSignByUserIdAndPlatform,err:", err)
		return sign, err
	}

	return sign, nil
}

func (model *UserLoginTokenModel) CleanAllLoginTokenOfUser(userIds ...int64) error {
	userTableMap := make(map[string][]int64, 3)
	for _, userId := range userIds {
		table := schema.SubtableUserId(userId, schema.UserLoginToken{}.TableName())
		userTableMap[table] = append(userTableMap[table], userId)
	}

	for table, uids := range userTableMap {
		dbRes := model.getDb().Unscoped().Table(table).Delete(&schema.UserLoginToken{}, "user_id in ?", uids)
		if err := dbRes.Error; err != nil {
			return fmt.Errorf("clean login token error: %v", err)
		}
	}

	return nil
}

func (model *UserLoginTokenModel) List(userIds ...int64) (tokens []*schema.UserLoginToken) {
	userTableMap := make(map[string][]int64, 3)
	for _, userId := range userIds {
		table := schema.SubtableUserId(userId, schema.UserLoginToken{}.TableName())
		userTableMap[table] = append(userTableMap[table], userId)
	}

	for table, uids := range userTableMap {
		ts := make([]*schema.UserLoginToken, 0, len(uids))
		model.getDb().Model(&schema.UserLoginToken{}).Table(table).Where("user_id in ?", uids).Find(&ts)
		tokens = append(tokens, ts...)
	}

	return
}
